package com.ajieee.merge.service.impl;

import com.ajieee.merge.entity.common.result.PageDTO;
import com.ajieee.merge.entity.finance.dto.KlinePatternQuery;
import com.ajieee.merge.entity.finance.dto.KlinePatternReqDTO;
import com.ajieee.merge.entity.finance.po.EtfQuotePO;
import com.ajieee.merge.entity.finance.po.KlinePatternPO;
import com.ajieee.merge.enums.common.DeleteFlag;
import com.ajieee.merge.exception.BizWarnException;
import com.ajieee.merge.mapper.EtfQuoteMapper;
import com.ajieee.merge.mapper.KlinePatternMapper;
import com.ajieee.merge.service.KlinePatternService;
import com.ajieee.merge.util.GroovyUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.*;

/**
 * @author ajieee
 * @date 2025-11-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class KlinePatternServiceImpl implements KlinePatternService {

	private final KlinePatternMapper klinePatternMapper;

	private final EtfQuoteMapper etfQuoteMapper;

	@Override
	public void save(KlinePatternReqDTO dto) {
		boolean exists = klinePatternMapper.exists(Wrappers.<KlinePatternPO>lambdaQuery()
				.eq(KlinePatternPO::getPatternCode, dto.getPatternCode())
				.eq(KlinePatternPO::getDeleted, DeleteFlag.NORMAL));
		if (exists) {
			throw BizWarnException.dataRepeated("该形态编码已存在");
		}

		KlinePatternPO po = new KlinePatternPO();
		BeanUtils.copyProperties(dto, po);
		klinePatternMapper.insert(po);
	}

	@Override
	public PageDTO<KlinePatternPO> list(KlinePatternQuery query) {
		Page<KlinePatternPO> page = klinePatternMapper.pageList(new Page<>(query.getCurrent(), query.getSize()), query);
		return PageDTO.from(page);
	}

	@Override
	public KlinePatternPO queryById(Long id) {
		return klinePatternMapper.selectById(id);
	}

	@Override
	public void update(KlinePatternReqDTO dto) {
		if (dto.getId() == null) {
			throw BizWarnException.paramError("ID不能为空");
		}

		KlinePatternPO po = new KlinePatternPO();
		BeanUtils.copyProperties(dto, po);
		klinePatternMapper.updateById(po);
	}

	@Override
	public List<LocalDate> backtest(String targetCode, String patternId) {
		Wrapper<EtfQuotePO> wrapper = Wrappers.<EtfQuotePO>lambdaQuery()
				.eq(EtfQuotePO::getFundCode, targetCode)
				.orderByAsc(EtfQuotePO::getDataDate);
		List<EtfQuotePO> quotes = etfQuoteMapper.selectList(wrapper);

		KlinePatternPO klinePattern = klinePatternMapper.selectById(patternId);
		if (klinePattern == null) {
			throw BizWarnException.paramError("形态ID错误");
		}

		Integer barNum = klinePattern.getBarNum();
		int size = quotes.size();
		if (size < barNum) {
			log.info("行情数量不足");
			return List.of();
		}

		List<LocalDate> result = new ArrayList<>();
		List<EtfQuotePO> used;
		for (int i = barNum - 1; i < size; i++) {
			used = quotes.subList(i, i + barNum);

			EtfQuotePO last = used.getLast();
			Map<String, ?> context = new HashMap<>() {{
				put("body", Math.abs(last.getClose() - last.getOpen()));
				put("upper", last.getHigh() - Math.max(last.getOpen(), last.getClose()));
				put("lower", Math.min(last.getOpen(), last.getClose()) - last.getLow());
				put("total", last.getHigh() - last.getLow());
			}};
			boolean execute = (boolean) GroovyUtils.execute(klinePattern.getScript(), context);
			if (execute) {
				result.add(last.getDataDate());
			}
		}

		return result;
	}
}
